package com.lry.netty01.server;

import com.lry.netty01.server.in.FrameDecoder;
import com.lry.netty01.server.in.PacketDecoder;
import com.lry.netty01.server.in.PacketHandler;
import com.lry.netty01.server.out.PacketEncoder;
import com.lry.netty01.server.queue.Task;
import com.lry.netty01.server.queue.TaskQueue;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class Client {

    private EventLoopGroup group;

    private Bootstrap bootstrap;

    @Autowired
    private TaskQueue taskQueue;

    private static Client client;

    @PostConstruct
    public void init() {
        client = this;
    }

    public void run(String[] args) throws InterruptedException {
        group = new NioEventLoopGroup();

        initBootstrap();

        execTaskQueue();

        connectToServer("localhost",9091);

        //注册钩子
        shutDownHook();
    }


    public static void offerTaskQueue(Task task){
        client.taskQueue.offerTask(task);
    }

    private void execTaskQueue() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                taskQueue.exec();
            }
        }).start();
    }

    private void initBootstrap(){
        bootstrap = new Bootstrap();
        bootstrap.group(group).channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.SO_KEEPALIVE, true);
        bootstrap.handler(new ChannelInitializer<Channel>() {
            @Override
            protected void initChannel(Channel ch) throws Exception {
                //处理粘包，半包问题
                ch.pipeline().addLast(new FrameDecoder(1024));

                //将字节转成java对象吗，反序列化
                ch.pipeline().addLast("decoder", new PacketDecoder());

                //将java对象转换字节，序列化
                ch.pipeline().addLast("encoder",new PacketEncoder());

                //报文处理器
                ch.pipeline().addLast("packetHandler",new PacketHandler());
            }
        });
    }


    public void connectToServer(String host, Integer port) {
        String key = host+":"+port;
        //连接
        bootstrap.connect(host,port).addListener((ChannelFuture futureListener) -> {
            final EventLoop eventLoop = futureListener.channel().eventLoop();
            if (!futureListener.isSuccess()) {
                //连接tcp服务器不成功 10后重连
                log.info(key + "连接失败!在10s之后准备尝试重连!");
                eventLoop.schedule(() -> connectToServer(host, port), 10, TimeUnit.SECONDS);
            }else {
                log.info("连接"+key+"成功");
            }
        });
    }


    private void shutDownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(()-> {
            log.info("链接关闭，开始释放资源");
            if(group!=null){
                group.shutdownGracefully();
            }
        }));
    }




}
